import React, { Component } from 'react';
import WPT from 'wpt';
import cx from 'classnames';
import showHide from '@wpt/showHide';
import DatePicker from './pickerDate';
import Frm2Picker from './pickerFromTo';
import s from './index.m.less';

const CACHE = {
    modal: null, // 当前弹窗
    registerBlurOk: false, // 是否已经注册失焦事件
    pickerFamily: new Set(['__fixed_key_for_picker_modal__']), // 工程内的所有同类picker实例
};
const FILL_ID = 'inpit-fill-height'; // 填充dom ID

@showHide
class PickerCore extends Component {
    componentDidMount() {
        this.onPageShow();
        CACHE.pickerFamily.add(this.key);
        // 把上级对象转为行内元素
        this.$dom.parentElement.style.display = 'inline-block';
    }

    componentWillReceiveProps(np) {
        // 当前已经打开拔盘，但不属于当前组件
        if (!CACHE.modal || CACHE.modal.uuid != this.key) return;

        if (np.value != this.props.value) {
            CACHE.modal && this.handelDate('propsChanged', np.value);
        }
    }

    componentWillUnmount() {
        this.onPageHide();
    }

    onPageShow = () => {
        if (!CACHE.registerBlurOk) {
            $('body').on('click', this.handleBlur);
            CACHE.registerBlurOk = true;
        }
    };

    onPageHide = () => {
        this.killModal('save');
        if (CACHE.registerBlurOk) {
            CACHE.registerBlurOk = false;
            $('body').off('click', this.handleBlur);
        }
    };

    handleBlur = e => {
        const { target = 0, currentTarget = 0 } = e || {};
        let $ele = target;
        if (!CACHE.modal) return;

        while ($ele !== currentTarget) {
            const { dataset = {} } = $ele;
            const { name } = dataset;
            if (name && CACHE.pickerFamily.has(name)) {
                return;
            }
            $ele = $ele.parentElement;
        }
        this.killModal('save');
    };

    killModal = order => {
        if (CACHE.modal) {
            order === 'save' && CACHE.modal.saveLastValue();
            CACHE.modal.close();
            CACHE.modal = 0;
        }
        $(`#${FILL_ID}`).remove();
    };

    key = WPT.Util.uuid();

    // 点取消时使用;
    originValue = this.props.value;

    onOk = () => {
        const { originValue } = this;
        this.originValue = this.props.value;
        this.props.onConfirm && this.props.onConfirm(originValue);
    };

    onCancel = () => {
        if (this.originValue != this.props.value) {
            this.props.onChange(this.originValue);
        }
        this.props.onCancel && this.props.onCancel();
    };

    getPopProps = () => {
        const {
            datas,
            title,
            cancelName,
            confirmName,
            confirmClass,
            value,
            beginTime,
            endTime,
            year,
            month,
            day,
            hour,
            min,
            onChange,
        } = this.props;

        const pickProp = {
            uuid: this.key,
            title,
            cancelName,
            confirmName,
            confirmClass,
            value,
            onChange,
            onCancel: this.onCancel,
            onOk: this.onOk,
        };

        if (datas) {
            // 通用数据
            Object.assign(pickProp, { datas });
        } else {
            // 日期组件数据
            Object.assign(pickProp, {
                beginTime,
                endTime,
                year,
                month,
                day,
                hour,
                min,
            });
        }
        return pickProp;
    };

    handelDateCheckBefore = (...args) => {
        const { beforeClick } = this.props;
        if (!beforeClick) {
            this.handelDate(...args);
            return;
        }

        beforeClick(() => {
            this.handelDate(...args);
        });
    };

    handelDate = (propsChanged, newValue) => {
        const pickProp = this.getPopProps();
        const Picker = this.picker || DatePicker;
        const { layer } = this.props;
        let { modal } = CACHE;
        const exePop = () => {
            this.killModal('save');
            CACHE.modal = WPT.Modal.open(<Picker {...pickProp} />, {
                onClose: this.killModal,
                position: 'bottom',
                animationType: 'dd',
                layer,
            });
            modal = CACHE.modal;
        };

        if (modal) {
            if (propsChanged === 'propsChanged') {
                // 用户转动拔盘
                pickProp.value = newValue;
            } else if (CACHE.modal.uuid === this.key) {
                // 重复点击
                return;
            }
            // 切换了新对象，判断是不是需要添加遮罩
            modal.isLayered == layer ? modal.updateState(<Picker {...pickProp} />) : exePop();
        } else {
            // 第一次打开弹窗时检查覆盖
            this.handleShield();
            exePop();
        }

        // 用户切换了同家族组件，执行回调保存上一家的数据
        if (modal.saveLastValue && modal.saveLastValue != this.onOk) {
            modal.saveLastValue();
        }
        modal.saveLastValue = this.onOk;
        modal.uuid = this.key;
        modal.isLayered = layer;
    };

    handleShield = () => {
        const DashboardHeight = 240; // 拔盘高度
        const screenHeight = window.innerHeight; // 屏幕高度
        const htmlLength = document.body.scrollHeight || document.documentElement.scrollHeight;
        const DashboardShieldLen = DashboardHeight - (screenHeight - this.$dom.getBoundingClientRect().bottom);
        const scrolledLength = $(window).scrollTop();
        const valildScrollUp = htmlLength - screenHeight - scrolledLength;
        if (valildScrollUp < DashboardShieldLen) {
            $('body').append(`<div style="height: ${DashboardShieldLen - valildScrollUp}px;" id="${FILL_ID}"></div>`);
        }
        DashboardShieldLen + scrolledLength > 0 && $(window).scrollTop(DashboardShieldLen + scrolledLength);
    };

    render() {
        const { className, value, children } = this.props;

        return (
            <div
                ref={ele => {
                    this.$dom = ele;
                }}
                onClick={this.handelDateCheckBefore}
                data-name={this.key}
                className={cx(s.wrap, { [className]: className, [s.placeholder]: !value })}
            >
                {children || '请选择'}
            </div>
        );
    }
}

class CommonScrollPicker extends PickerCore {
    static defaultProps = {
        title: '',
        value: 0, // 这个值为datas的实例成员
        beforeClick: null, // 响应点击事件前的回调，预检查是否允许调用,是：next()，默认否
        onChange: null, // 拔盘每次滚动时调用，返回当前值，点取消时返回最初的值
        onConfirm: null, // 确定，在失去焦点及点击确定时回调，可以不填，返回旧值
        onCancel: null, // 点取消时的回调，可省略，
        cancelName: '取消',
        confirmName: '确定',
        layer: false, // true,蒙层
        children: '', // dom 元素
        datas: false, // 通用选择器里显示的数据，['hello','stanley'], 或者[{name:'hello',id:1},{name:'stanley',id:2}]
    };

    constructor(p) {
        super(p);
        const { datas } = p;
        if (!(datas instanceof Array) || datas.length <= 1) {
            throw new Error('datas必须为长度大于1的数组！');
        }
        const item = datas[0];
        if (typeof item !== 'string') {
            if (typeof item !== 'object' || !item.name) {
                throw new Error('datas数组成员必须为字符串,或者{name:"xxx", ...} ！');
            }
        }
    }
}

class DateScrollPicker extends PickerCore {
    static defaultProps = {
        title: '',
        value: 0, // stamp,秒时间戳
        beforeClick: null, // 响应点击事件前的回调，预检查是否允许调用,是：next()，默认否
        onChange: null, // 拔盘每次滚动时调用，返回当前值，点取消时返回最初的值
        onConfirm: null, // 确定，在失去焦点及点击确定时回调，可以不填，返回旧值
        onCancel: null, // 点取消时的回调，可省略，
        cancelName: '取消',
        confirmName: '确定',
        confirmClass: null,
        beginTime: null, // 开始时间’2017-1-2 8:03'，或者秒时间戳s
        endTime: null, // 结束时间’2021/12/31 21:59'，或者秒时间戳s
        layer: false, // true,蒙层
        children: '', // dom 元素

        // true时显示下面项目，同时最多三个
        year: false, // 显示年
        month: false, // 显示月
        day: false, // 显示天
        hour: false, // 显示小时
        min: false, // 显示分
    };

    constructor(p) {
        super(p);
        if (
            typeof p.value !== 'number'
            || p.value < new Date(1900, 1, 1).getTime() / 1000
            || p.value > new Date(2100, 1, 1).getTime() / 1000
        ) {
            throw new Error('value必须为秒时间戳！');
        }
    }
}

class From2Picker extends PickerCore {
    static defaultProps = {
        title: '',
        type: 'user', // user | year | month | day | hour | min | second
        beforeClick: null, // 响应点击事件前的回调，预检查是否允许调用,是：next()，默认否
        onChange: null, // 拔盘每次滚动时调用，返回当前值，点取消时返回最初的值
        onConfirm: null, // 确定，在失去焦点及点击确定时回调，可以不填，返回旧值
        onCancel: null, // 点取消时的回调，可省略，
        cancelName: '取消',
        confirmName: '确定',
        middle: '至', // 中间的字
        value: [], // 值，数字数组
        unit: '', // 单位; 当type=| year | month | day | hour | min | second 时不用填
        beginNumber: undefined, // 开始数字
        endNumber: undefined, // 结束数字
        layer: false, // true,蒙层
        children: '', // dom 元素
    };

    picker = Frm2Picker;

    getPopProps = () => {
        const {
            title,
            type,
            value,
            cancelName,
            confirmName,
            unit,
            beginNumber,
            endNumber,
            middle,
            onChange,
        } = this.props;

        return {
            uuid: this.key,
            type,
            title,
            value,
            cancelName,
            confirmName,
            unit,
            beginNumber,
            endNumber,
            middle,
            onChange,
            onCancel: this.onCancel,
            onOk: this.onOk,
        };
    };
}

export default {
    CommonScrollPicker,
    DateScrollPicker,
    From2Picker,
};
